﻿using System;
using System.Collections.Generic;
using SeaBattle.Domain.Abstract;
using SeaBattle.Domain.Entities;
using System.Linq;
using SeaBattle.Domain.Abstract.Services;
using System.IO;

namespace SeaBattle.Domain.Concrete
{
    public class FakeGameRepository: IGameRepository
    {

        private IPlayerService playerService;
        private IPlayerRepository playerRepository;
        private IShipRepository shipRepository;
        private IFleetRepository fleetRepository;
        private IAccountService accountService;

        /// <summary>
        /// Initializes a new instance of the <see cref="FakeGameRepository"/> class.
        /// </summary>
        /// <param name="playerService">The player service.</param>
        /// <param name="shipRepository">The ship repository.</param>
        /// <param name="fleetRepository">The fleet repository.</param>
        /// <param name="playerRepository">The player repository.</param>
        /// <remarks></remarks>
        public FakeGameRepository(IPlayerService playerService, IShipRepository shipRepository,
            IFleetRepository fleetRepository, IPlayerRepository playerRepository, IAccountService accountService)
        {
            this.playerService = playerService;
            this.shipRepository = shipRepository;
            this.fleetRepository = fleetRepository;
            this.playerRepository = playerRepository;
            this.accountService = accountService;
            InitializeGames();
        }
        
        /// <summary>
        /// fake game storage to avoid GC affects
        /// </summary>
        private static List<Game> games = new List<Game>();

        /// <summary>
        /// generates next id value upon the fake storage
        /// </summary>
        /// <returns>generated id value</returns>
        private int GetNextId()
        {
            if(games.Count == 0)
                return 1;
            return (games[games.Count-1].Id + 1);
        }

        /// <summary>
        /// creates new game instance with creator player specified
        /// </summary>
        /// <param name="creator">creator player</param>
        /// <returns>created game instance</returns>
        public Game CreateNewGame(Player creator,int balance)
        {
            return new Game(GetNextId(), DateTime.Now, creator, shipRepository, fleetRepository, playerRepository) {Preset = balance, Opened = true };
        }

        /// <summary>
        /// save current game instance to the storage
        /// </summary>
        /// <param name="game">game instance</param>
        /// <returns>successful saving flag</returns>
        public bool SaveGame(Game game)
        {
            if (!games.Contains(game))
            {
                games.Add(game);
            }
            return true;
        }


        /// <summary>
        /// Loads the game.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <returns></returns>
        public Game GetGame(int id)
        {
            return games.FirstOrDefault(x => x.Id == id);
        }

        /// <summary>
        /// Initializes the games
        /// </summary>
        private void InitializeGames()
        {
            if (games.Count == 0)
            {
                var tmpGame2 = new Game(6, DateTime.Now, playerService.GetPlayer("vasya"), shipRepository, fleetRepository, playerRepository) 
                { Preset = 300, Opened = true };
                tmpGame2.JoinOpponent(playerService.GetPlayer("andrew"));
                string[] str2 = new string[20];

                str2[0] = "0	0	0	0	-2	1	-2	0	-2	1";
                str2[1] = "0	0	0	0	-2	1	-2	-2	-2	-2";
                str2[2] = "0	0	-2	-2	-2	1	-2	1	-2	0";
                str2[3] = "0	0	-2	2	-2	-2	-2	-2	-2	-2";
                str2[4] = "0	0	-2	2	-2	1	-2	3	3	3";
                str2[5] = "0	0	-2	-2	-2	-2	-2	-2	-2	-2";
                str2[6] = "0	0	-2	1	-2	2	2	-2	-2	4";
                str2[7] = "0	0	-2	-2	-2	-2	-2	-2	-2	4";
                str2[8] = "-2	-2	-2	0	0	0	0	0	-2	4";
                str2[9] = "2	2	-2	0	0	0	0	0	-2	4";
                str2[10] = "-2	-2	-2	-2	-2	-2	0	0	0	0";
                str2[11] = "-2	1	-2	1	1	-2	0	0	0	0";
                str2[12] = "-2	-2	-2	-2	-2	-2	0	0	0	0";
                str2[13] = "-2	-2	-2	1	-2	0	0	0	0	0";
                str2[14] = "1	-2	-2	-2	-2	-2	-2	-2	0	0";
                str2[15] = "-2	-2	1	-2	1	1	1	-2	0	0";
                str2[16] = "1	-2	-2	-2	-2	-2	-2	-2	0	0";
                str2[17] = "1	-2	1	1	-2	-2	1	-2	0	0";
                str2[18] = "-2	-2	-2	-2	-2	-2	1	-2	0	0";
                str2[19] = "1	1	1	1	-2	-2	1	-2	0	0";
                //----------------------//
                var tmpGame = new Game(5,DateTime.Now, playerService.GetPlayer("vasya"), shipRepository, fleetRepository, playerRepository) 
                { Preset = 200, Opened = true};
                tmpGame.Opponent = playerService.GetPlayer("andrew");
                tmpGame.GameClosing(playerService.GetPlayer("vasya"));
                tmpGame.realField[tmpGame.Creator] = new Field(10);
                tmpGame.realField[tmpGame.Opponent] = new Field(10);
                tmpGame.BoardStates[tmpGame.Creator] = BoardSetupState.STATEEND;
                tmpGame.BoardStates[tmpGame.Opponent] = BoardSetupState.STATEEND;
                tmpGame.ChangePreset = true;
                string[] str = new string[20];

                str[0] = "0	0	0	0	-2	8	-2	0	-2	8";
                str[1] = "0	0	0	0	-2	8	-2	-2	-2	-2"; 
                str[2] = "0	0	-2	-2	-2	8	-2	8	-2	0";
                str[3] = "0	0	-2	2	-2	-2	-2	-2	-2	-2";
                str[4] = "0	0	-2	2	-2	8	-2	3	3	3";
                str[5] = "0	0	-2	-2	-2	-2	-2	-2	-2	-2";
                str[6] = "0	0	-2	1	-2	2	2	-2	-2	4";
                str[7] = "0	0	-2	-2	-2	-2	-2	-2	-2	4";
                str[8] = "-2	-2	-2	0	0	0	0	0	-2	4";
                str[9] = "2	2	-2	0	0	0	0	0	-2	4";
                str[10] = "-2	-2	-2	-2	-2	-2	0	0	0	0";
                str[11] = "-2	8	-2	8	8	-2	0	0	0	0";
                str[12] = "-2	-2	-2	-2	-2	-2	0	0	0	0";
                str[13] = "-2	-2	-2	8	-2	0	0	0	0	0";
                str[14] = "8	-2	-2	-2	-2	-2	-2	-2	0	0";
                str[15] = "-2	-2	8	-2	8	8	8	-2	0	0";
                str[16] = "8	-2	-2	-2	-2	-2	-2	-2	0	0";
                str[17] = "8	-2	8	8	-2	-2	8	-2	0	0";
                str[18] = "-2	-2	-2	-2	-2	-2	8	-2	0	0";
                str[19] = "8	8	8	8	-2	-2	8	-2	0	0";

                
                    for(int i = 0; i < 10; i++)
                    {
                        //winner
                
                        string[] tmp = str[i].Split('\t');
                        string[] tmp2 = str2[i].Split('\t');
                        for (int j = 0; j < 10; j++)
                        {
                            tmpGame2.realField[tmpGame2.Creator].AField[i, j] = (FieldType)Enum.Parse(typeof(FieldType), tmp2[j]);
                            tmpGame.realField[tmpGame.Winner].AField[i, j] = (FieldType)Enum.Parse(typeof(FieldType), tmp[j]);
                        }
                    }
                    for (int i = 0; i < 10; i++)
                    {
                        //loser

                        string[] tmp = str[i+10].Split('\t');
                        string[] tmp2 = str2[i + 10].Split('\t');
                        for (int j = 0; j < 10; j++)
                        {
                            tmpGame2.realField[tmpGame2.Opponent].AField[i, j] = (FieldType)Enum.Parse(typeof(FieldType), tmp2[j]);
                            tmpGame.realField[tmpGame.Opponent].AField[i, j] = (FieldType)Enum.Parse(typeof(FieldType), tmp2[j]);
                        }
                    }

                    tmpGame2.BoardStates[tmpGame2.Creator] = tmpGame2.BoardStates[tmpGame2.Opponent] = BoardSetupState.STATEEND;
                    tmpGame2.Start();


                games.Add(new Game(1, DateTime.Now, playerService.GetPlayer("vasya"),shipRepository,fleetRepository, playerRepository) { Preset = 100, Opened = true });
                games.Add(tmpGame);
                games.Add(tmpGame2);
                games.Add(new Game(3, DateTime.Now, playerService.GetPlayer("andrew"), shipRepository,fleetRepository, playerRepository) { Preset = 300, Opened = true });
                games.Add(new Game(4, DateTime.Now, playerService.GetPlayer("vasya"), shipRepository,fleetRepository, playerRepository) { Preset = 400, Opened = true });
            }
        }


        /// <summary>
        /// Gets the games.
        /// </summary>
        /// <remarks></remarks>
        public IList<Game> Games
        {
            get { return games.AsReadOnly(); }
        }



        public bool DeleteGame(int id)
        {
            var game = GetGame(id);
            var preset = game.Preset;
            var owner = game.Creator;
            var currentBalance = accountService.GetPlayerBalance(owner);

            if (game.State == GameState.STATE_OPENED)
                accountService.SetPlayerBalance(owner, currentBalance + preset);
            games.Remove(game);

            return true;
        }
    }
}
